package network

import (
	"context"
	"fmt"
	"net"

	"gitee.com/doraemon1996/bunny/goroutine"
	"gitee.com/doraemon1996/bunny/log"
	"gitee.com/doraemon1996/bunny/uuid"
)

// TCP监听器
type TCPListener struct {
	listener

	rawLn *net.TCPListener // 底层监听器
}

// 新建TCP监听器
func NewTCPListener(ctx context.Context, network, address string) (ln *TCPListener, err Error) {
	addr, underlyingErr := net.ResolveTCPAddr(network, address)
	if underlyingErr != nil {
		err = &networkError{ErrorType_Underlying, underlyingErr}
		return
	}

	rawLn, underlyingErr := net.ListenTCP(network, addr)
	if underlyingErr != nil {
		err = &networkError{ErrorType_Underlying, underlyingErr}
		return
	}

	ln = new(TCPListener)
	ln.id = uuid.GenUint64()
	ln.network = network
	ln.address = address
	ln.rawLn = rawLn
	ln.ctl.Init(ctx, nil)

	return
}

// 获取监听器类型
func (ln *TCPListener) Type() ListenerType {
	return Listener_TCP
}

// 获取底层监听器
func (ln *TCPListener) RawListener() any {
	return ln.rawLn
}

// 开始运行监听器的循环逻辑
func (ln *TCPListener) Start(f OnConnect) {
	ln.ctl.Start(func() {
		ln.ctl.Add(1)
		goroutine.Submit(func() {
			defer ln.ctl.Done()

			// 监听器没有关闭,需要持续监听
			for ln.ctl.Opening() {
				ln.acceptLoop(f)
			}
		})
	})
}

// 停止并关闭监听器
// 使用监听器了Context或派生Context的地方都在影响范围内
func (ln *TCPListener) Stop() {
	ln.ctl.Stop(func() {
		log.Infof("%v is about to exit", ln)

		if ln.rawLn != nil {
			if err := ln.rawLn.Close(); err != nil {
				log.Errorf("TCPListener close underlying listener catch error: %v", err)
			}
		}

		ln.ctl.Wait()
	})
}

// 端口监听循环
func (ln *TCPListener) acceptLoop(f OnConnect) {
	var (
		err  error
		conn *net.TCPConn
	)

	defer func() {
		if val := recover(); val != nil {
			err = fmt.Errorf("%v", val)
		}

		if err != nil {
			log.Errorf("TCPListener underlying listener accept catch error: %v", err)
		}
	}()

	for !ln.ctl.Closed() {
		conn, err = ln.rawLn.AcceptTCP()
		if err != nil {
			// 主动退出屏蔽错误信息
			if ln.ctl.Closed() {
				err = nil
			}
			break
		}

		f(NewTCPConn(ln, conn))
	}
}
